/*
 * SearchService.cpp
 *
 *  Created on: Mar 12, 2011
 *      Author: kmueller
 */

#include "SearchService.h"

#include "Main.h"

#include "../core/Opennav.h"
#include "../core/Location.h"

#include <QtCore>
#include <QGeoCoordinate>

using namespace opennav;
using namespace QtMobility;

SearchService::SearchService(opennav::Map* m) {
	map = m;

	request = NULL;
	result = NULL;

	start();
	setPriority(QThread::IdlePriority);
}

SearchService::~SearchService() {
	terminate();
	delete result;
	wait();
}

void SearchService::run() {
	while (isRunning()) {

		mutex.lock();

		if (request != NULL) {
			if (result != NULL) {
				delete result;
				result = NULL;
			}
			switch (request->getType()) {
			case SearchRequest::CITY: {
				SearchCityRequest* search =
						dynamic_cast<SearchCityRequest*> (request);
				request = NULL;
				mutex.unlock();

				opennav::SearchCityResult searchResult;
				map->search_city(search->getString().toStdString(),
						search->getCountryId(), searchResult);
				delete search;

				result = new CityResult(searchResult, this);
				emit resultAvailable(result);
			}
				break;
			case SearchRequest::STREET: {
				SearchStreetRequest* search =
						dynamic_cast<SearchStreetRequest*> (request);
				request = NULL;
				mutex.unlock();

				opennav::SearchRoadResult searchResult;
				map->search_road(search->getString().toStdString(),
						search->getCityId(), searchResult);
				delete search;

				result = new StreetResult(searchResult, this);
				emit resultAvailable(result);
			}
				break;
			}
		} else {
			mutex.unlock();
			msleep(500);
		}
	}
}

void SearchService::searchCity(QString& city, int countryId) {
	mutex.lock();
	request = new SearchCityRequest(city, countryId);
	mutex.unlock();
}

void SearchService::searchStreet(QString& street, int cityId) {
	mutex.lock();
	request = new SearchStreetRequest(street, cityId);
	mutex.unlock();
}

/****************************************/

SearchService::SearchCityRequest::SearchCityRequest(QString& name, int c) {
	city = name;
	country = c;
}

QString SearchService::SearchCityRequest::getString() {
	return city;
}

int SearchService::SearchCityRequest::getCountryId() {
	return country;
}

SearchService::SearchRequest::RequestType SearchService::SearchCityRequest::getType() {
	return CITY;
}

/****************************************/

SearchService::SearchStreetRequest::SearchStreetRequest(QString& name, int c) {
	street = name;
	city = c;
}

QString SearchService::SearchStreetRequest::getString() {
	return street;
}

int SearchService::SearchStreetRequest::getCityId() {
	return city;
}

SearchService::SearchRequest::RequestType SearchService::SearchStreetRequest::getType() {
	return STREET;
}

/****************************************/

SearchService::CityResult::CityResult(opennav::SearchCityResult& result,
		SearchService* parent) :
	QAbstractListModel(NULL) {
	for (int i = 0; i < result.count(); i++) {
		opennav::City city;
		parent->map->get_result(i, result, city);
		data_.append(city);
	}
}

int SearchService::CityResult::rowCount(const QModelIndex &parent) const {
	return data_.size();
}

int SearchService::CityResult::getCityId(int id) const {
	return data_.at(id).city_id;
}

LabeledCoordinate SearchService::CityResult::get(int id) const{
	opennav::City city = data_.at(id);
	opennav::Coordinate coord;
	Main::getInstance().getMap().geocode(city, coord);
	LabeledCoordinate coordinate(getCityName(city), QGeoCoordinate(coord.dlatitude(), coord.dlongitude()));
	return coordinate;
}

QString SearchService::CityResult::getCityName(const opennav::City& city) const{
	opennav::Region region;
	Main::getInstance().getMap().region(city.region_id, region);
	return QString(city.name.c_str()).append(" (").append(QString(region.name.c_str())).append(")");
}

QVariant SearchService::CityResult::data(const QModelIndex &index, int role) const {
	if (!index.isValid())
		return QVariant();

	if (index.row() >= data_.size())
		return QVariant();

	if (role == Qt::DisplayRole)
		return QString(getCityName(data_.at(index.row())));
	else
		return QVariant();

}

QVariant SearchService::CityResult::headerData(int section,
		Qt::Orientation orientation, int role) const {
	if (role != Qt::DisplayRole)
		return QVariant();

	if (orientation == Qt::Horizontal)
		return QString("Column %1").arg(section);
	else
		return QString("Row %1").arg(section);
}

/****************************************/

SearchService::StreetResult::StreetResult(opennav::SearchRoadResult& result,
		SearchService* parent) :
	QAbstractListModel(NULL) {
	for (int i = 0; i < result.count(); i++) {
		opennav::Road road;
		parent->map->get_result(i, result, road);
		data_.append(road);
	}
}

int SearchService::StreetResult::rowCount(const QModelIndex &parent) const {
	return data_.size();
}

int SearchService::StreetResult::getRoadId(int id) const {
	return data_.at(id).road_id;
}

LabeledCoordinate SearchService::StreetResult::get(int id) const {
	opennav::Road road = data_.at(id);
	opennav::Coordinate coord;
	Main::getInstance().getMap().geocode(road, coord);
	LabeledCoordinate coordinate(getStreetName(road), QGeoCoordinate(coord.dlatitude(), coord.dlongitude()));
	return coordinate;
}

QString SearchService::StreetResult::getStreetName(const opennav::Road& street) const{
	opennav::City city;
	Main::getInstance().getMap().city(street.city_id, city);
	return QString(city.name.c_str()).append(" - ").append(QString(street.labels.at(0).c_str()));
}

QVariant SearchService::StreetResult::data(const QModelIndex &index, int role) const {
	if (!index.isValid())
		return QVariant();

	if (index.row() >= data_.size())
		return QVariant();

	if (role == Qt::DisplayRole)
		return getStreetName(data_.at(index.row()));
	else
		return QVariant();
}

QVariant SearchService::StreetResult::headerData(int section,
		Qt::Orientation orientation, int role) const {
	if (role != Qt::DisplayRole)
		return QVariant();

	if (orientation == Qt::Horizontal)
		return QString("Column %1").arg(section);
	else
		return QString("Row %1").arg(section);
}
